package com.sunlands.zlcx.usercenter.service.task;

import com.sunlands.zlcx.usercenter.common.annotation.AutoLog;
import com.sunlands.zlcx.usercenter.domain.UsersDO;
import com.sunlands.zlcx.usercenter.exception.BusinessException;
import com.sunlands.zlcx.usercenter.exception.SendExceptionUtil;
import com.sunlands.zlcx.usercenter.service.UsersServiceImpl;
import com.sunlands.zlcx.usercenter.service.VipUserServiceImpl;
import com.sunlands.zlcx.usercenter.util.SimpleLockUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.util.List;

import static com.sunlands.zlcx.usercenter.config.RedisConfig.CacheKeys.VIP_TIME_PRE_CHARGING;

@Service
@Slf4j
public class TaskVipChargingServiceImpl {

    @Autowired
    private VipUserServiceImpl vipUserService;
    @Autowired
    private UsersServiceImpl usersService;
    @Autowired
    private SimpleLockUtil simpleLockUtil;
    @Autowired
    private SendExceptionUtil sendExceptionUtil;
    @Resource(name = "vipChargingExecutor")
    private ThreadPoolTaskScheduler vipChargingExecutor;
    @Value("${eureka.debug:false}")
    private Boolean debug;

    /**
     * vip预扣费
     */
    @AutoLog
    @Scheduled(cron = "${scheduled.preChargingVipTime}")
    public void preChargingVipTime() {
        if (debug || sendExceptionUtil.getSysdev().toLowerCase().equals("pre")) {
            log.warn("本地环境不启动定时");
            return;
        }

        if (!getPreChargingVipTimeLock()) {
            return;
        }
        log.info("VIP预扣费，定时任务开始");
        int i = 0;
        Page<UsersDO> page = null;
        try {
            StopWatch stopWatch = new StopWatch();
            while (i == 0 || page.hasNext()) {
                stopWatch.start("开始");
                Pageable pageable = new PageRequest(i, 100);
                i++;
                page = usersService.findAllLiveUsers(pageable);
                List<UsersDO> vipUserDOS = page.getContent();
                for (UsersDO user : vipUserDOS) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    vipChargingExecutor.execute(() -> {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        preReduceTime(user.getId());
                    });
                }
                stopWatch.stop();
                log.info("VIP预扣费，定时任务，本次处理数据条数 size = {} 总条数 = {} 耗时 = {}", page.getContent().size(), page.getTotalElements(), stopWatch.getTotalTimeMillis());
            }
        } catch (Exception e) {
            sendExceptionUtil.sendException("VIP预扣费，定时任务 Exception: " + e.getMessage(), new BusinessException());
            log.error("VIP预扣费，定时任务", e);
            log.error("", e);
        } finally {
            releasePreChargingVipTimeLock();
        }
    }





    /**
     * 封装此方法，是为了给加速方法使用用来触发AOP事物，在同一个service下调用方法，无法触发
     */
    public void preReduceTime(Long userId) {
        vipUserService.preReduceTime(userId);
    }

    private boolean getPreChargingVipTimeLock() {
        String lockKey = VIP_TIME_PRE_CHARGING;

        try {
            return simpleLockUtil.acquireLock(lockKey, this.getClass().getName(), 1000 * 60 * 2);
        } catch (Exception e) {
            log.error("", e);
        }
        return false;
    }

    private void releasePreChargingVipTimeLock() {
        String lockKey = VIP_TIME_PRE_CHARGING;
        try {
            simpleLockUtil.releaseLock(lockKey, this.getClass().getName());
        } catch (Exception e) {
            log.error("releaseSendGoodsLockKey error", e);
        }
    }

}